/**
 * 
 */
package eMdP.colisions;

import java.util.logging.Logger;

import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.util.Timer;
import com.jmex.bui.BLabel;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.contact.ContactCallback;
import com.jmex.physics.contact.PendingContact;

import eMdP.classesBasiques.Bustia;
import eMdP.classesBasiques.Escenari;
import eMdP.classesBasiques.Furgoneta;
import eMdP.classesBasiques.Paquet;
import eMdP.classesBasiques.Personatge;
import eMdP.classesBasiques.PersonatgeNJ;
import eMdP.estats.Partida;
import eMdP.gestors.GestorConstants;
import eMdP.gestors.GestorMusica;
import eMdP.gestors.GestorPantalla;

/**
 * Implementació de una funció de CallBack, que serà l'encarregada de controlar-nos les físiques dels nodes dinàmics de la 
 * nostra aplicació. En el nostre cas tindrem dos tipus de nodes dinàmics: els paquets i el jugador. 
 * A través d'aquesta classe haurem de controlar totes les col·lisions del nostre joc:
 * Col·lisions:
 * 	1. Paquet contra Personatge.
 *  2. Paquet contra PNJ.
 *  3. Paquet contra Bústia del mateix color.
 *  4. Paquet contra Bústia d'un color diferent.
 *  5. Personatge contra PNJ.
 *  6. Personatge contra Furgoneta
 *  7. Personatge quan no col·lisioni amb res, per tal d'anular-li les forces, perqué no comenci a rebotar per la pantalla.
 *  
 * @author redribbon
 *
 */
public class ImplCallBack {
	
	private static final Logger logger = Logger.getLogger(Partida.class.getName());

	//private Personatge p;
		
	/**
     * Constructor de la CallBack, per els quals li passarem l'espai físic i el rootNode, perquè pugui fer les operacions necessaries.
     */
    public ImplCallBack(final PhysicsSpace espaiFisic, final Node rootNode) {
    	
    	  ContactCallback myCallBack = new ContactCallback() {				
              public boolean adjustContact( PendingContact c ) {
            	  boolean bustiaMala=false;
            	  //System.out.println(c.getNode1().getParent().getName()+" vs. "+c.getNode2().getParent().getName());
            	  // Primer de tot separarem les col·lisions en dos grans blocs, les que hi participa un Paquet, i les del Personatge.
            	  // Començarem amb els Paquets
            	  try{
            	  if(c.getNode1().getName().contains("Paquet") || c.getNode2().getName().contains("Paquet")){
            		  // Col·lisió 1 -> Paquet contra Personatge
            		  // La col·lisió 2 serà la mateixa que la 1, ja que els PNJ son Persoantges
            		  //System.out.println(c.getNode1().getName()+" vs. "+c.getNode2().getName());
            		  if(c.getNode1().getParent().getName().contains("Personatge") || c.getNode2().getParent().getName().contains("Personatge")){
            			  Personatge p; Paquet paq;
            			  if(c.getNode1().getName().contains("Paquet"))
            			  {
            				  paq = (Paquet)c.getNode1().getParent();
            				  p = (Personatge)c.getNode2().getParent();
            			  }
            			  else
            			  {
            				  paq = (Paquet)c.getNode2().getParent();
            				  p = (Personatge)c.getNode1().getParent();
            			  }
            			  collisio1o2(c,paq,p);
            		  }
            		  
            		  if(c.getNode1().getParent().getName().contains("NJ") || c.getNode2().getParent().getName().contains("NJ")){
            			  PersonatgeNJ p; Paquet paq;
            			  if(c.getNode1().getName().contains("Paquet"))
            			  {
            				  paq = (Paquet)c.getNode1().getParent();
            				  p = (PersonatgeNJ)c.getNode2().getParent();
            			  }
            			  else
            			  {
            				  paq = (Paquet)c.getNode2().getParent();
            				  p = (PersonatgeNJ)c.getNode1().getParent();
            			  }
            			  collisio2(c,paq,p);
            		  }
            		  // Col·lisió contra bústia
            		  else if(c.getNode1().getName().contains("Bustia") || c.getNode2().getName().contains("Bustia")){
            			  Paquet paq;
            			  Bustia bus;
            			  if(c.getNode1().getName().contains("Bustia"))
            			  {
            				  paq = (Paquet)c.getNode2().getParent();
            				  bus = (Bustia)c.getNode1().getParent();
            			  }
            			  else
            			  {
            				  paq = (Paquet)c.getNode1().getParent();
            				  bus = (Bustia)c.getNode2().getParent();
            			  }
            			  System.out.println("Paquet contra Bustia!!!!!");
            			  //Comprovem el color de la bústia i el paquet
            			  if(bus.getColor() == paq.getColor())
            			  {
            				// Col·lisió 3 -> Paquet contra Bústia del mateix color

            				collisio3(c,paq,bus);
            			  }else{
            				// Col·lisió 4 -> Paquet contra Bústia de un color diferent
            			    collisio4(c,paq,bus);
            			    bustiaMala=true;
            			    System.out.println("Em cambiat la id del jugador a: "+paq.getIdJugador());
            			  }
            		  }
            		  //Si el paquet col·lisiona amb un node estàtic s'ha d'eliminar
            		  if((c.getNode1().isStatic() || c.getNode2().isStatic()) && !bustiaMala){
                		  Paquet paq;
                		  if(c.getNode1().isStatic()) paq = (Paquet)c.getNode2().getParent();
                		  else paq = (Paquet)c.getNode1().getParent();
                		  
                		  eliminarPaquet(paq);
                	  }
            	  }
            	  // Seguim amb les col·lisions del personatge
            	  else if(c.getNode1().getParent().getName().contains("Personatge") || c.getNode2().getParent().getName().contains("Personatge"))
            	  {
            			  // Col·lisió 5 -> Personatge contra PNJ
            			  if( c.getNode1().getName().contains("NJ") || c.getNode2().getName().contains("NJ")){
            				  Personatge p; PersonatgeNJ pNJ;
            				  if(c.getNode1().getName().contains("NJ")){
            					  p = (Personatge)c.getNode2().getParent();
            					  pNJ = (PersonatgeNJ)c.getNode1().getParent(); 
            				  }else{
            					  p = (Personatge)c.getNode1().getParent();
            					  pNJ = (PersonatgeNJ)c.getNode2().getParent(); 
            				  }
            				  p.netejarFisiques();
            				  collisio5(c,p,pNJ);
            			  }
            			  // Col·lisió 6 -> Personatge contra Furgoneta
            			  else if(c.getNode1().getName().contains("Correus") || c.getNode2().getName().contains("Correus")){
            				  Personatge p;
            				  Furgoneta furgo;
            				  if(c.getNode1().getName().contains("Correus")){
            					  p = (Personatge)c.getNode2().getParent();
            					  furgo = (Furgoneta)c.getNode1().getParent(); 
            				  }else{
            					  p = (Personatge)c.getNode1().getParent();
            					  furgo = (Furgoneta)c.getNode2().getParent(); 
            				  }
            				  p.netejarFisiques();
            				  collisio6(c,p,furgo);
            				  
            			  }
            			  else{
            				  //Netejem sempre les físiques, ja que sino rebota,bota,...
            				  Personatge p;
            				  if(c.getNode1().getName().contains("Personatge"))
            					  p = (Personatge)c.getNode1().getParent();
            				  else
            					  p = (Personatge)c.getNode2().getParent();
            				  
            				  p.netejarFisiques();
            			  }
            	  }
            	  }catch(Exception e){//System.out.println("Peta a alguna consulta, però segueix funcionant?");
            	  }
            	 
	              return true;
              }
              
              /** Mètode que executarem al succeir la col·lisió 1 o 2
               *  1.- Paquet contra Personatge
               *  2.- Paquet contra PNJ
               * @param c La PendingContact
               */
              private void collisio1o2(PendingContact c,Paquet paq, Personatge p){
            	  //System.out.println(c.getNode1().getName()+"Paquet xoca amb un PErsonatge jugador o no"+c.getNode2().getName());
            	  logger.info("CALLBACK::Col·lisiona Personatge contra Paquet. Tipus 2 o 5. idjug:"+paq.getIdJugador());
        		  if(!p.isImmune(Timer.getTimer().getTimeInSeconds()) && paq.getIdJugador() != p.getIdJugador()) //SI el jugador no és immune, li afecten els paquets
        		  {   
        			 System.out.println("Hauriem d'eliminar paquets al jugador!!!"); 
            		  // Eliminem 2 paquets del jugador
        			  // System.out.println("aqui arrivem perfi "+persona.quantsPaquets());
            		  int cont=0;
            		  // En cas de ser un PNJ no tindrà paquet i no entrerà al bucle
            		  while(p.getNumPaquets() > 1 && cont < 2){
            			  // Eliminem l'últim paquet del personatge
            			  //p.getPaquets().removeLast();
            			  
            			  paq = p.retornarEliminarPaquet();
	  			    	  paq.getNodeFisic().setMass(0.5f);
	  			    	  p.getParent().attachChild(p);
	  			          paq.setActive(true);
	  			    	  paq.setHaEstatLlançat(true);
	  			    	  paq.clearDynamics();
	  			    	  paq.setIdJugador(5);
            			  
            			  cont++;
            			  ((BLabel)GestorPantalla.getLlista().getLast().getFinestra().getComponent(4*p.getIdJugador()+4)).setText(""+p.getNumPaquets());
            		  }
            		  //System.out.println("Bloquejem el Personatge!!!!!!:Paquet contra Personatge o PNJ");
            		  p.bloquejar(Timer.getTimer().getTimeInSeconds()+2);  //Esperem 2 segons sense poder moure el jugador
      	    		 //Hauriem de carregar una animació del Jugador estabilitzant-se
        		  }
              }

              
              /** Mètode que executarem al succeir la col·lisió 2
               *  2.- Paquet contra PNJ
               * @param c La PendingContact
               */
              private void collisio2(PendingContact c,Paquet paq, Personatge p){
            	  //System.out.println(c.getNode1().getName()+"Paquet xoca amb un PErsonatge jugador o no"+c.getNode2().getName());
            	  logger.info("CALLBACK::Col·lisiona PersonatgeNJ contra Paquet. Tipus 2.");
        		  if(!p.isImmune(Timer.getTimer().getTimeInSeconds()) && paq.getIdJugador() != p.getIdJugador()) //SI el jugador no és immune, li afecten els paquets
        		  {   
            		  p.bloquejar(Timer.getTimer().getTimeInSeconds()+5);  //Esperem 2 segons sense poder moure el jugador
        		  }
              }
              
              
              /** Mètode que executarem al succeir la col·lisió 3
               *  3.- Paquet contra Bústia del mateix color
               * @param c La PendingContact
               */
              private void collisio3(PendingContact c, Paquet paq, Bustia bus){
            	  //System.out.println("Paquet ha xocat contra bústia bona");
            	  logger.info("CALLBACK::Col·lisiona Paquet contra bustia Bona. Tipus 6.");
    			  paq.setActive(false);
    			  paq.getLocalTranslation().set(-20,-8,-20);
    			  //El fill 0 del rootNode és l'escenari, que d'ell pengen tots els jugadors, els jugadors comencen a la pos 1
    			  Personatge p = (Personatge)((Escenari)rootNode.getChild(0)).getChild(paq.getIdJugador()+1);
    			  
    			  p.paquetEntrat();
    			  //música que el paquet ha entrat a la bústia correcte!
    			
    			  paq.getNodeFisic().delete();
    			  paq.getParent().detachChild(paq);
    			  //System.out.println("Despres de matar, ha introduit: "+p.quantsPaquetsHaEntrat()+" paquets.");
    			  ((BLabel)GestorPantalla.getLlista().getLast().getFinestra().getComponent(4*p.getIdJugador()+2)).setText(""+p.quantsPaquetsHaEntrat());
    			  
              }
              
              /** Mètode que executarem al succeir la col·lisió 4
               *  4.- Paquet contra Bústia de colors diferents
               * @param c La PendingContact
               */
              private void collisio4(PendingContact c, Paquet paq, Bustia bus){
            	  System.out.println("Paquet ha xocat contra bústia de color diferent");
            	  /* Col·lisió tipus 7 -> Paquet contra Bústia Dolenta */
    			  logger.info("CALLBACK::Col·lisiona Paquet contra bustia Dolenta. Tipus 4.");
    			  GestorMusica.reproduirSoColisio(0,bus.getWorldTranslation());
    			  Vector3f dirForsa = new Vector3f();
    			  int idJug = paq.getIdJugador();
    			  System.out.println("abans d'agafarPersonatge!");
    			  Personatge p = (Personatge)((Escenari)(rootNode.getChild(0))).getChild(idJug+1);
    			  System.out.println("Després d'agafarPersonatge!");
//        		  dirForsa.set(p.getNodeEstatic().getWorldTranslation());
//        		  dirForsa.subtractLocal(bus.getWorldTranslation());
    			  dirForsa.set(p.getLocalTranslation());
    			  dirForsa.subtractLocal(bus.getLocalTranslation());
    			  dirForsa.multLocal(600);
        		  //dirForsa.addLocal(0, 3f, 0);
    			  dirForsa.y=300;
    			  paq.setIdJugador(5); //Cambiem la id del jugador perquè pugui col·lisionar amb aquest
    			  //System.out.println("Patataaaaaaaaaaaaa :"+paq.getIdJugador());
    			  paq.clearDynamics();
        		  paq.addForce(dirForsa);
        		  paq.setHaEstatLlançat(true);
              }
              
              /** Mètode que executarem al succeir la col·lisió 5
               *  5.- Personatge contra PNJ
               * @param c La PendingContact
               */
              private void collisio5(PendingContact c, Personatge p, PersonatgeNJ pNJ){
            	  System.out.println("Xoquem amb un PNJ");
            	  System.out.println("DeteccioColisions::Col·lisionem amb un PNJ");
					logger.info("COL·LISIONS::Jugador" + p.getIdJugador()+ " ha colisionat amb PNJ. Tipus 1."+ pNJ.getName());
					/* Comprovem que el Personatge no està bloquejat */
					if (!p.estaBloquejat(Timer.getTimer().getTimeInSeconds())) {
						/* Si el PNJ està bloquejat no passa res per col·lisionar amb ell */
						if (!pNJ.estaBloquejat(Timer.getTimer().getTimeInSeconds())) {
							/* Si cap dels dos està bloquejat, blocagem els dos */
							p.bloquejar(Timer.getTimer().getTimeInSeconds() + 8);
							pNJ.bloquejar(Timer.getTimer().getTimeInSeconds() + 14);
						}
					}
              }
              
              
              /** Mètode que executarem al succeir la col·lisió 6
               *  6.- Personatge contra Furgoneta
               * @param c La PendingContact
               */
              private void collisio6(PendingContact c, Personatge p, Furgoneta furgo){
            	  //System.out.println("Xoquem amb furgo");
				  //Fem la descarrega de paquets
				  
				 //Si el personatge no te cap paquet i la furgo pot descarregar, fem el descarrega
				  if (p.getNumPaquets() < 1 && furgo.potDescarregar()) { 
						/* Comprovem que el jugador no estigui bolquejat */
						if (!p.estaBloquejat(Timer.getTimer().getTimeInSeconds())) {
							/* Carreguem:: Reproduim musica de col·lisio, bloquegem el jugador i el posem immune, i carreguem 4 Paquets */ 
							//GestorMusica.reproduirSoColisio(0, furgonetes.get(k).getLocalTranslation());
							p.setImmune(Timer.getTimer().getTimeInSeconds() + 6); 
							p.bloquejar(Timer.getTimer().getTimeInSeconds() + 3.5f);
							p.carregar(espaiFisic,GestorConstants.NUM_PAQUETS_CARREGAMENT);
							/* Indiquem a la furgoneta que ha fet una descàrrega */
							furgo.unCarregamentFet(Timer.getTimer().getTimeInSeconds());
							((BLabel)GestorPantalla.getLlista().getLast().getFinestra().getComponent(4*p.getIdJugador()+4)).setText(""+p.getNumPaquets());
						}else System.out.println("el personatge està bloqujat i no pot carregar");
				  }//else System.out.println("el personatge te "+p.getNumPaquets()+" paquets, o furgo no pot descarregar: "+furgo.potDescarregar());
            	  
              }
              
              /**
               * Mètode per eliminar els paquets que ja han col·lisionat i queden morts per l'escenari
               * 
               */
              private void eliminarPaquet(Paquet paq){
            	  try{
	            	  if(!paq.estaMort()){
	            		  if(paq.sestaAutodestruint()){
	            			  if(paq.matar(Timer.getTimer().getTimeInSeconds())){
	            				  logger.info("CALLBACK::Eliminem el Paquet "+paq.getName());
	            				  paq.setActive(false);
	            				  paq.getNodeFisic().setIsCollidable(false);
	            				  paq.getNodeFisic().delete();
	            				  paq.mort();
	            				  Node n = (Node)paq.getParent();
	            				  if(n.hasChild(paq)){
	            					  n.detachChild(paq);
	            				  }
	            				  
	            			  }
	            		  }else{
	            			  paq.autodestruirme(Timer.getTimer().getTimeInSeconds(), 3.5f);
	            			  
	            		  }
	        		  }
            	  }catch(Exception e){System.out.println("El paquet ja està eliminat");}
              }
          };
          
          espaiFisic.getContactCallbacks().add( myCallBack );

    }
 
}
